package com.zz.server.handle;

import com.zz.common.config.Constants;
import com.zz.common.entity.Information;
import com.zz.common.enums.MessageType;
import com.zz.common.handle.executor.MessageExecutor;
import com.zz.common.handle.executor.MessageExecutorFactory;
import com.zz.common.protocol.TunnelProtocol;
import com.zz.common.utils.ObjectUtil;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.util.concurrent.AbstractEventExecutorGroup;
import io.netty.util.internal.EmptyArrays;
import lombok.extern.slf4j.Slf4j;

import java.util.Map;
import java.util.Objects;
import java.util.Optional;

/**
 * 服务端端处理类
 *
 * @author zz
 */
@Slf4j
public class ServerChannelHandler extends SimpleChannelInboundHandler<TunnelProtocol> {


    @Override
    public void channelWritabilityChanged(ChannelHandlerContext context) throws Exception {
        Channel localChannel = context.channel().attr(Constants.Attributes.LOCAL_CHANNEL).get();
        ObjectUtil.setReadable(localChannel, context.channel().isWritable());
        super.channelWritabilityChanged(context);
    }
    @Override
    public void exceptionCaught(ChannelHandlerContext context, Throwable cause) throws Exception {
        log.error("server channel exception:{}", cause.getMessage());
        context.close();
    }
    @Override
    protected void channelRead0(ChannelHandlerContext context, TunnelProtocol protocolMsg) throws Exception {
        MessageExecutor executor =
                MessageExecutorFactory.getMessageExecutor(MessageType.getMessageType(protocolMsg.getType()));
        if (Objects.isNull(executor)) {
            log.info("错误！找不到对应的消息处理器！messageType:{}", protocolMsg.getType());
            return;
        }
        executor.execute(new Information(context, protocolMsg));
    }

    /**
     * 连接中断
     */
    @Override
    public void channelInactive(ChannelHandlerContext context) throws Exception {
        log.info("server channel inactive");
        Channel localChannel = context.channel().attr(Constants.Attributes.LOCAL_CHANNEL).getAndSet(Constants.Objects.CHANNEL_NULL);
        if (ObjectUtil.isNotNull(localChannel)) {
            localChannel.attr(Constants.Attributes.SERVER_CHANNEL).set(Constants.Objects.CHANNEL_NULL);
            localChannel.close();
        }
        Map<String, Channel> channelCache = context.channel().attr(Constants.Attributes.CHANNEL_CACHE).getAndSet(Constants.Objects.MAP_NULL);
        if (ObjectUtil.isNotEmpty(channelCache)) {
            channelCache.values().forEach(Channel::close);
        }
    }

}
